/*
 * QRCodeReaderViewController
 *
 * Copyright 2014-present Yannick Loriot.
 * http://yannickloriot.com
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in
 * all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
 * THE SOFTWARE.
 *
 */

#import "FFCaptureViewController.h"
#import "FFQRCameraSwitchButton.h"
#import "FFQRCodeReaderView.h"
#import "FFQRCodeResourceUtils.h"
#import "FFScanResult.h"

#define mainHeight [[UIScreen mainScreen] bounds].size.height
#define mainWidth [[UIScreen mainScreen] bounds].size.width
#define navBarHeight self.navigationController.navigationBar.frame.size.height

@interface FFCaptureViewController ()<AVCaptureMetadataOutputObjectsDelegate, FFQRCodeReaderViewDelegate, UIImagePickerControllerDelegate, UINavigationControllerDelegate>
@property(strong, nonatomic) FFQRCameraSwitchButton *switchCameraButton;
@property(strong, nonatomic) FFQRCodeReaderView *cameraView;
@property(strong, nonatomic) AVAudioPlayer *beepPlayer;
@property(strong, nonatomic) UIButton *cancelButton;

@property(strong, nonatomic) UIImageView *imgLine;
@property(strong, nonatomic) UIImageView *img1;
@property(strong, nonatomic) UIImageView *img2;
@property(strong, nonatomic) UIImageView *img3;
@property(strong, nonatomic) UIImageView *img4;

@property(strong, nonatomic) UILabel *lblTip;

@property(strong, nonatomic) AVCaptureDevice *defaultDevice;
@property(strong, nonatomic) AVCaptureDeviceInput *defaultDeviceInput;
@property(strong, nonatomic) AVCaptureDevice *frontDevice;
@property(strong, nonatomic) AVCaptureDeviceInput *frontDeviceInput;
@property(strong, nonatomic) AVCaptureMetadataOutput *metadataOutput;
@property(strong, nonatomic) AVCaptureSession *session;
@property(strong, nonatomic) AVCaptureVideoPreviewLayer *previewLayer;

@property(strong, nonatomic) CIDetector *detector;

@property(copy, nonatomic) void (^completionBlock)(NSString *, NSString *);

@property(copy, nonatomic) void (^callback)(FFScanResult *result);

@property(nonatomic, strong) FFScanConfig *config;
@end

@implementation FFCaptureViewController

#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wimplicit-retain-self"

- (void)dealloc {
    NSLog(@"dealloc");
}

/**
 -[MTLDebugDevice newTextureWithDescriptor:iosurface:plane:]:2403: failed assertion `Texture Descriptor Validation
 IOSurface textures must use MTLStorageModeShared
 */
//Edit Scheme -> Run -> Diagnostics -> Metal API Validation -> Turn it off.

- (instancetype)initWithConfig:(FFScanConfig *)config {
    self = [super init];
    if (self) {
        _beepPlayer = [[AVAudioPlayer alloc] initWithData:[FFQRCodeResourceUtils wavDataFromCustomBundle:@"beep"] error:nil];
        _config = config;
    }
    return [self initWithCancelButtonTitle:NSLocalizedString(@"Cancel", @"Cancel")];
}

- (id)initWithScanConfig:(FFScanConfig *)config resultCallBack:(void (^)(FFScanResult *result))callback {
    self.callback = callback;

    return [self initWithConfig:config];
}

- (id)initWithCancelButtonTitle:(NSString *)cancelTitle {
    self.view.backgroundColor = [UIColor blackColor];
    [self setupAVComponents];
    [self configureDefaultComponents];
    [self setupUIComponentsWithCancelButtonTitle:cancelTitle];
    [self setupAutoLayoutConstraints];
    [_cameraView.layer insertSublayer:self.previewLayer atIndex:0];

    return self;
}

+ (instancetype)readerWithCancelButtonTitle:(NSString *)cancelTitle {
    return [[self alloc] initWithCancelButtonTitle:cancelTitle];
}

- (void)viewDidLoad {
    [super viewDidLoad];

    self.navigationItem.rightBarButtonItem = [[UIBarButtonItem alloc] initWithTitle:@"相册" style:UIBarButtonItemStylePlain target:self action:@selector(clickRightBarButton:)];
    self.navigationItem.rightBarButtonItem.tintColor = [UIColor whiteColor];

    UILabel *titleLabel = [[UILabel alloc] initWithFrame:CGRectMake(0, 20, 100, 44)];
    titleLabel.backgroundColor = [UIColor clearColor];
    titleLabel.font = [UIFont boldSystemFontOfSize:17];
    titleLabel.textColor = [UIColor whiteColor];
    titleLabel.textAlignment = NSTextAlignmentCenter;
    titleLabel.text = @"扫描二维码";  //设置标题
    self.navigationItem.titleView = titleLabel;

    //    NSDictionary *attributes=[NSDictionary dictionaryWithObjectsAndKeys:[UIColor whiteColor],NSForegroundColorAttributeName,nil];
    //    [self.navigationController.navigationBar setTitleTextAttributes:attributes];
}

- (void)back {
    [self.navigationController popViewControllerAnimated:YES];
}

- (void)viewWillAppear:(BOOL)animated {
    [super viewWillAppear:animated];

    if (self.config.isTouchBtnScan) {
        [self stopScanning];
    } else {
        [self startScanning];
    }
}

- (void)viewWillDisappear:(BOOL)animated {
    [self stopScanning];
    [super viewWillDisappear:animated];
}

- (void)viewWillLayoutSubviews {
    [super viewWillLayoutSubviews];

    _previewLayer.frame = self.view.bounds;
}

- (BOOL)shouldAutorotate {
    return YES;
}

- (void)loadView:(CGRect)rect {
    _imgLine.frame = CGRectMake(0, _cameraView.innerViewRect.origin.y, mainWidth, 12);
}

#pragma mark - Managing the Orientation

- (void)willRotateToInterfaceOrientation:(UIInterfaceOrientation)toInterfaceOrientation duration:(NSTimeInterval)duration {
    [super willRotateToInterfaceOrientation:toInterfaceOrientation duration:duration];

    [_cameraView setNeedsDisplay];

    if (self.previewLayer.connection.isVideoOrientationSupported) {
        self.previewLayer.connection.videoOrientation = [[self class] videoOrientationFromInterfaceOrientation:toInterfaceOrientation];
    }
}

+ (AVCaptureVideoOrientation)videoOrientationFromInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation {
    switch (interfaceOrientation) {
        case UIInterfaceOrientationLandscapeLeft:
            return AVCaptureVideoOrientationLandscapeLeft;
        case UIInterfaceOrientationLandscapeRight:
            return AVCaptureVideoOrientationLandscapeRight;
        case UIInterfaceOrientationPortrait:
            return AVCaptureVideoOrientationPortrait;
        default:
            return AVCaptureVideoOrientationPortraitUpsideDown;
    }
}

#pragma mark - Managing the Block

- (void)setCompletionWithBlock:(void (^)(NSString *resultAsString, NSString *type))completionBlock {
    self.completionBlock = completionBlock;
}

#pragma mark - Initializing the AV Components

- (void)setupUIComponentsWithCancelButtonTitle:(NSString *)cancelButtonTitle {
    self.cameraView = [[FFQRCodeReaderView alloc] init];
    _cameraView.topDistance = self.config.areaTop;
    _cameraView.translatesAutoresizingMaskIntoConstraints = NO;
    _cameraView.clipsToBounds = YES;
    _cameraView.delegate = self;
    [self.view addSubview:_cameraView];

    if (_frontDevice) {
        _switchCameraButton = [[FFQRCameraSwitchButton alloc] init];
        [_switchCameraButton setTranslatesAutoresizingMaskIntoConstraints:false];
        [_switchCameraButton addTarget:self action:@selector(switchCameraAction:) forControlEvents:UIControlEventTouchUpInside];
        [self.view addSubview:_switchCameraButton];
        _switchCameraButton.hidden = YES;
    }

    self.cancelButton = [[UIButton alloc] init];
    self.cancelButton.hidden = YES;
    _cancelButton.translatesAutoresizingMaskIntoConstraints = NO;
    [_cancelButton setTitle:cancelButtonTitle forState:UIControlStateNormal];
    [_cancelButton setTitleColor:[UIColor grayColor] forState:UIControlStateHighlighted];
    [_cancelButton addTarget:self action:@selector(cancelAction:) forControlEvents:UIControlEventTouchUpInside];
    [self.view addSubview:_cancelButton];

    CGFloat c_width = mainWidth - 100;
    CGFloat s_height = mainHeight - 40;
    CGFloat y = (s_height - c_width) / 2 - s_height / 6 + 20;

    _lblTip = [[UILabel alloc] initWithFrame:CGRectMake(0, y + 40 + c_width + self.config.areaTop, mainWidth, 15)];
    _lblTip.text = @"将二维码放入框内 即可自动扫描";
    _lblTip.textColor = [UIColor whiteColor];
    _lblTip.font = [UIFont systemFontOfSize:13];
    _lblTip.textAlignment = NSTextAlignmentCenter;
    [self.view addSubview:_lblTip];

    if (self.config.isTouchBtnScan) {
        UIButton *btn = [[UIButton alloc] initWithFrame:CGRectMake(50, CGRectGetMaxY(_lblTip.frame) + 10, mainWidth - 100, 40)];
        btn.selected = NO;
        btn.backgroundColor = [UIColor lightGrayColor];
        btn.alpha = 0.3;
        [btn setTitle:self.config.touchBtnText forState:UIControlStateNormal];
        [btn setTitleColor:[UIColor whiteColor] forState:UIControlStateNormal];
        [btn setTitle:@"停止扫描" forState:UIControlStateSelected];
        [btn setTitleColor:[UIColor redColor] forState:UIControlStateSelected];
        [btn addTarget:self action:@selector(clickStartBtn:) forControlEvents:UIControlEventTouchUpInside];
        [self.view addSubview:btn];
    }

    CGFloat corWidth = 16;
    CGFloat offsetTop = 0;

    _img1 = [[UIImageView alloc] initWithFrame:CGRectMake(49, y + 26 + self.config.areaTop + offsetTop, corWidth, corWidth)];
    _img1.image = [FFQRCodeResourceUtils imagesNamedFromCustomBundle:@"QRCode_cor1"];
    //img1.image = [UIImage imageNamed:@"QRCode_cor1.png"];

    [self.view addSubview:_img1];

    _img2 = [[UIImageView alloc] initWithFrame:CGRectMake(35 + c_width, y + 26 + self.config.areaTop + offsetTop, corWidth, corWidth)];
    _img2.image = [FFQRCodeResourceUtils imagesNamedFromCustomBundle:@"QRCode_cor2"];

    [self.view addSubview:_img2];

    _img3 = [[UIImageView alloc] initWithFrame:CGRectMake(49, y + c_width + 14 + self.config.areaTop + offsetTop, corWidth, corWidth)];
    _img3.image = [FFQRCodeResourceUtils imagesNamedFromCustomBundle:@"QRCode_cor3"];
    [self.view addSubview:_img3];

    _img4 = [[UIImageView alloc] initWithFrame:CGRectMake(35 + c_width, y + c_width + 14 + self.config.areaTop + offsetTop, corWidth, corWidth)];
    _img4.image = [FFQRCodeResourceUtils imagesNamedFromCustomBundle:@"QRCode_cor4"];

    [self.view addSubview:_img4];

    _imgLine = [[UIImageView alloc] init];
    _imgLine.image = [FFQRCodeResourceUtils imagesNamedFromCustomBundle:@"QRCodeScanLine"];

    [self.view addSubview:_imgLine];
}

- (void)setupAutoLayoutConstraints {
    NSDictionary *views = NSDictionaryOfVariableBindings(_cameraView, _cancelButton);

    [self.view addConstraints:
                   [NSLayoutConstraint constraintsWithVisualFormat:@"V:|[_cameraView][_cancelButton(0)]|"
                                                           options:0
                                                           metrics:nil
                                                             views:views]];
    [self.view addConstraints:
                   [NSLayoutConstraint constraintsWithVisualFormat:@"H:|[_cameraView]|"
                                                           options:0
                                                           metrics:nil
                                                             views:views]];
    [self.view addConstraints:
                   [NSLayoutConstraint constraintsWithVisualFormat:@"H:|-[_cancelButton]-|"
                                                           options:0
                                                           metrics:nil
                                                             views:views]];

    if (_switchCameraButton) {
        NSDictionary *switchViews = NSDictionaryOfVariableBindings(_switchCameraButton);

        [self.view addConstraints:
                       [NSLayoutConstraint constraintsWithVisualFormat:@"V:|[_switchCameraButton(50)]"
                                                               options:0
                                                               metrics:nil
                                                                 views:switchViews]];
        [self.view addConstraints:
                       [NSLayoutConstraint constraintsWithVisualFormat:@"H:[_switchCameraButton(70)]|"
                                                               options:0
                                                               metrics:nil
                                                                 views:switchViews]];
    }
}

- (void)setupAVComponents {
    //    NSDictionary *detectorOptions = @{ CIDetectorAccuracy : CIDetectorTracking };
    //    CIDetector *idetector = [CIDetector detectorOfType:CIDetectorTypeQRCode context:nil options:detectorOptions];

    self.defaultDevice = [AVCaptureDevice defaultDeviceWithMediaType:AVMediaTypeVideo];

    if (_defaultDevice) {
        self.defaultDeviceInput = [AVCaptureDeviceInput deviceInputWithDevice:_defaultDevice error:nil];
        self.metadataOutput = [[AVCaptureMetadataOutput alloc] init];
        //_metadataOutput.metadataObjectTypes = @[AVMetadataObjectTypeQRCode];

        self.session = [[AVCaptureSession alloc] init];
        self.previewLayer = [AVCaptureVideoPreviewLayer layerWithSession:self.session];
        //    _previewLayer.videoGravity = AVLayerVideoGravityResizeAspectFill;

#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wdeprecated-declarations"

        for (AVCaptureDevice *device in [AVCaptureDevice devicesWithMediaType:AVMediaTypeVideo]) {
            if (device.position == AVCaptureDevicePositionFront) {
                self.frontDevice = device;
            }
        }

#pragma clang diagnostic pop

        if (_frontDevice) {
            self.frontDeviceInput = [AVCaptureDeviceInput deviceInputWithDevice:_frontDevice error:nil];
        }
    }

    //[self configOutputRect:NO];
}

- (void)configOutputRect:(BOOL)isFullScreen {
    if (isFullScreen) {
        [_metadataOutput setRectOfInterest:CGRectMake(0, 0, 1, 1)];
    } else {
        CGFloat c_width = mainWidth - 100;
        CGFloat s_height = mainHeight - 40;
        CGFloat y = (s_height - c_width) / 2 - s_height / 6;
        CGRect rect = CGRectMake(50, y + 26 + self.config.areaTop, c_width, c_width);
        CGRect intertRect = [_previewLayer metadataOutputRectOfInterestForRect:rect];
        [_metadataOutput setRectOfInterest:intertRect];
    }
}

- (void)configureDefaultComponents {
    [_session addOutput:_metadataOutput];

    if (_defaultDeviceInput) {
        [_session addInput:_defaultDeviceInput];
    }

    [_metadataOutput setMetadataObjectsDelegate:self queue:dispatch_get_main_queue()];
    if ([[_metadataOutput availableMetadataObjectTypes] containsObject:AVMetadataObjectTypeQRCode] || [[_metadataOutput availableMetadataObjectTypes] containsObject:AVMetadataObjectTypeEAN13Code] ||
        [[_metadataOutput availableMetadataObjectTypes] containsObject:AVMetadataObjectTypeEAN8Code] ||
        [[_metadataOutput availableMetadataObjectTypes] containsObject:AVMetadataObjectTypeCode128Code]) {
        //设置读取类型
        if (self.config.scanType == FFScanTypeALL) {
            [_metadataOutput setMetadataObjectTypes:@[ AVMetadataObjectTypeQRCode, AVMetadataObjectTypeEAN13Code, AVMetadataObjectTypeEAN8Code, AVMetadataObjectTypeCode128Code ]];
        } else if (self.config.scanType == FFScanTypeQRCODE) {
            [_metadataOutput setMetadataObjectTypes:@[ AVMetadataObjectTypeQRCode ]];
        } else if (self.config.scanType == FFScanTypeBARCODE) {
            [_metadataOutput setMetadataObjectTypes:@[ AVMetadataObjectTypeEAN13Code, AVMetadataObjectTypeEAN8Code, AVMetadataObjectTypeCode128Code ]];
        }
    }
    [_previewLayer setVideoGravity:AVLayerVideoGravityResizeAspectFill];
    [_previewLayer setFrame:self.view.bounds];
    [self.view.layer addSublayer:_previewLayer];
    if ([_previewLayer.connection isVideoOrientationSupported]) {
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wdeprecated-declarations"

        _previewLayer.connection.videoOrientation = [[self class] videoOrientationFromInterfaceOrientation:self.interfaceOrientation];

#pragma clang diagnostic pop
    }

    //[self configOutputRect:NO];
}

- (void)switchDeviceInput {
    if (_frontDeviceInput) {
        [_session beginConfiguration];

        AVCaptureDeviceInput *currentInput = [_session.inputs firstObject];
        [_session removeInput:currentInput];

        AVCaptureDeviceInput *newDeviceInput = (currentInput.device.position == AVCaptureDevicePositionFront) ? _defaultDeviceInput : _frontDeviceInput;
        [_session addInput:newDeviceInput];

        [_session commitConfiguration];
    }
}

#pragma mark - Catching Button Events

- (void)clickStartBtn:(UIButton *)btn {
    btn.selected = !btn.selected;
    if (btn.selected) {
        [self startScanning];
    } else {
        [self stopScanning];
    }
}

- (void)cancelAction:(UIButton *)button {
    [self stopScanning];

    if (_completionBlock) {
        _completionBlock(nil, nil);
    }

    if (_callback) {
        _callback(nil);
    }

    //  if (_delegate && [_delegate respondsToSelector:@selector(captureControllerDidCancel:)]) {
    //    [_delegate captureControllerDidCancel:self];
    //  }
}

- (void)switchCameraAction:(UIButton *)button {
    [self switchDeviceInput];
}

#pragma mark - Controlling Reader

- (void)startScanning;
{
    dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
      if (![self.session isRunning]) {
          [self.session startRunning];
          [self configOutputRect:NO];
      }

      [self addAnimationAboutScan];
    });
}

- (void)stopScanning;
{
    dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
      if ([self.session isRunning]) {
          [self.session stopRunning];
      }

      [self removeAnimationAboutScan];
    });
}

#pragma mark - AVCaptureMetadataOutputObjects Delegate Methods

- (void)captureOutput:(AVCaptureOutput *)captureOutput didOutputMetadataObjects:(NSArray *)metadataObjects fromConnection:(AVCaptureConnection *)connection {
    for (AVMetadataObject *current in metadataObjects) {
        if ([current isKindOfClass:[AVMetadataMachineReadableCodeObject class]] && (
                                                                                       [[_metadataOutput availableMetadataObjectTypes] containsObject:AVMetadataObjectTypeEAN13Code] ||
                                                                                       [[_metadataOutput availableMetadataObjectTypes] containsObject:AVMetadataObjectTypeEAN8Code] ||
                                                                                       [[_metadataOutput availableMetadataObjectTypes] containsObject:AVMetadataObjectTypeCode128Code])) {
            NSString *scannedResult = [(AVMetadataMachineReadableCodeObject *)current stringValue];
            NSLog(@"二维码类型：%@", current.type);
            [self stopScanning];

            if (_completionBlock) {
                if (self.config.needSuccessBeepSound) {
                    [_beepPlayer play];
                }
                _completionBlock(scannedResult, current.type);
            }
            if (_callback) {
                if (self.config.needSuccessBeepSound) {
                    [_beepPlayer play];
                }
                FFScanResult *result = [[FFScanResult alloc] init];
                if ([current.type containsString:@"QRCode"]) {
                    result.type = SCAN_RESULT_TYPE_QRCODE;
                } else {
                    result.type = SCAN_RESULT_TYPE_BARCODE;
                }
                result.format = current.type;
                result.result = scannedResult;

                _callback(result);
            }
            break;
        }
    }
}

#pragma mark - Checking the Metadata Items Types

+ (BOOL)isAvailable {
    @autoreleasepool {
        AVCaptureDevice *captureDevice = [AVCaptureDevice defaultDeviceWithMediaType:AVMediaTypeVideo];

        if (!captureDevice) {
            return NO;
        }

        NSError *error;
        AVCaptureDeviceInput *deviceInput = [AVCaptureDeviceInput deviceInputWithDevice:captureDevice error:&error];

        if (!deviceInput || error) {
            return NO;
        }

        AVCaptureMetadataOutput *output = [[AVCaptureMetadataOutput alloc] init];

        if (!([output.availableMetadataObjectTypes containsObject:AVMetadataObjectTypeQRCode] || [output.availableMetadataObjectTypes containsObject:AVMetadataObjectTypeEAN13Code] ||
              [output.availableMetadataObjectTypes containsObject:AVMetadataObjectTypeEAN8Code] ||
              [output.availableMetadataObjectTypes containsObject:AVMetadataObjectTypeCode128Code])) {
            return NO;
        }

        return YES;
    }
}

#pragma mark - Checking RightBarButtonItem
- (void)clickRightBarButton:(UIBarButtonItem *)item {
    //self.detector = [CIDetector detectorOfType:CIDetectorTypeQRCode context:nil options:@{ CIDetectorAccuracy : CIDetectorAccuracyHigh }];
    UIImagePickerController *picker = [[UIImagePickerController alloc] init];
    picker.delegate = self;
    picker.allowsEditing = NO;
    picker.sourceType = UIImagePickerControllerSourceTypePhotoLibrary;
    [self presentViewController:picker animated:YES completion:nil];
}

#pragma mark - UIImagePickerControllerDelegate
- (void)imagePickerController:(UIImagePickerController *)picker didFinishPickingMediaWithInfo:(NSDictionary *)info {
    [picker dismissViewControllerAnimated:YES
                               completion:^{
                                 [self scanQrcodeWithImageInfo:info];
                               }];
}

- (void)scanQrcodeWithImageInfo:(NSDictionary *)info {
    NSString *mediaType = [info objectForKey:UIImagePickerControllerMediaType];
    if ([mediaType isEqualToString:@"public.image"]) {
        UIImage *originImage = [info objectForKey:UIImagePickerControllerEditedImage];

        if (!originImage) {
            originImage = [info objectForKey:UIImagePickerControllerOriginalImage];
        }
        [self recognizeQRCode:originImage];
    }
}

- (void)recognizeQRCode:(UIImage *)image {
    NSDictionary *detectorOptions = @{CIDetectorAccuracy : CIDetectorAccuracyHigh};
    CIContext *context = [CIContext contextWithOptions:nil];
    CIDetector *idetector = [CIDetector detectorOfType:CIDetectorTypeQRCode context:context options:detectorOptions];
    //    UIImage *fitImage = [self imageCompressForWidth:image targetWidth:mainWidth];
    //    UIImage *fitImage = [self imageCompressWithImage:image];
    NSArray *features = [idetector featuresInImage:[CIImage imageWithCGImage:image.CGImage]];
    if (features.count >= 1) {
        CIQRCodeFeature *feature = [features objectAtIndex:0];
        NSString *scannedResult = feature.messageString;
        if (_completionBlock) {
            [_beepPlayer play];
            _completionBlock(scannedResult, nil);
        }

        if (_callback) {
            if (self.config.needSuccessBeepSound) {
                [_beepPlayer play];
            }
            FFScanResult *result = [[FFScanResult alloc] init];
            result.result = scannedResult;

            _callback(result);
        }

        //        if (_delegate && [_delegate respondsToSelector:@selector(captureController:didScanResult:)]) {
        //            [_delegate captureController:self didScanResult:scannedResult];
        //        }
    }
}

- (UIImage *)imageCompressWithImage:(UIImage *)theImage {
    UIImage *bigImage = theImage;
    float actualHeight = bigImage.size.height;
    float actualWidth = bigImage.size.width;
    float newWidth = 0;
    float newHeight = 0;
    if (actualWidth > actualHeight) {
        //宽图
        newHeight = 256.0f;
        newWidth = actualWidth / actualHeight * newHeight;
    } else {
        //长图
        newWidth = 256.0f;
        newHeight = actualHeight / actualWidth * newWidth;
    }
    CGRect rect = CGRectMake(0.0, 0.0, newWidth, newHeight);
    UIGraphicsBeginImageContext(rect.size);
    [bigImage drawInRect:rect];  // scales image to rect
    theImage = UIGraphicsGetImageFromCurrentImageContext();
    UIGraphicsEndImageContext();
    //RETURN
    return theImage;
}

//指定宽度的等比例压缩
- (UIImage *)imageCompressForWidth:(UIImage *)sourceImage targetWidth:(CGFloat)defineWidth {
    UIImage *newImage = nil;
    CGSize imageSize = sourceImage.size;
    CGFloat width = imageSize.width;
    CGFloat height = imageSize.height;
    CGFloat targetWidth = defineWidth;
    CGFloat targetHeight = height / (width / targetWidth);
    CGSize size = CGSizeMake(targetWidth, targetHeight);
    CGFloat scaleFactor = 0.0;
    CGFloat scaledWidth = targetWidth;
    CGFloat scaledHeight = targetHeight;
    CGPoint thumbnailPoint = CGPointMake(0.0, 0.0);
    if (CGSizeEqualToSize(imageSize, size) == NO) {
        CGFloat widthFactor = targetWidth / width;
        CGFloat heightFactor = targetHeight / height;
        if (widthFactor > heightFactor) {
            scaleFactor = widthFactor;
        } else {
            scaleFactor = heightFactor;
        }
        scaledWidth = width * scaleFactor;
        scaledHeight = height * scaleFactor;
        if (widthFactor > heightFactor) {
            thumbnailPoint.y = (targetHeight - scaledHeight) * 0.5;
        } else if (widthFactor < heightFactor) {
            thumbnailPoint.x = (targetWidth - scaledWidth) * 0.5;
        }
    }
    UIGraphicsBeginImageContext(size);
    CGRect thumbnailRect = CGRectZero;
    thumbnailRect.origin = thumbnailPoint;
    thumbnailRect.size.width = scaledWidth;
    thumbnailRect.size.height = scaledHeight;

    [sourceImage drawInRect:thumbnailRect];

    newImage = UIGraphicsGetImageFromCurrentImageContext();
    if (newImage == nil) {
        NSLog(@"scale image fail");
    }

    UIGraphicsEndImageContext();
    return newImage;
}

#pragma mark - 扫码line滑动动画

- (CABasicAnimation *)animationWith:(id)fromValue toValue:(id)toValue repCount:(CGFloat)repCount duration:(CGFloat)duration {
    CABasicAnimation *lineAnimation = [CABasicAnimation animationWithKeyPath:@"transform.translation.y"];
    lineAnimation.fromValue = fromValue;
    lineAnimation.toValue = toValue;
    lineAnimation.repeatCount = repCount;
    lineAnimation.duration = duration;
    lineAnimation.fillMode = kCAFillModeForwards;
    lineAnimation.timingFunction = [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionLinear];
    return lineAnimation;
}

- (void)removeAnimationAboutScan {
    dispatch_async(dispatch_get_main_queue(), ^{
      if (![_imgLine.layer animationForKey:@"LineImgViewAnimation"]) {
          return;
      }
      [_imgLine.layer removeAnimationForKey:@"LineImgViewAnimation"];
      _imgLine.hidden = true;
    });
}
- (void)addAnimationAboutScan {
    /*
     _imgLine.frame = CGRectMake(0, _cameraView.innerViewRect.origin.y, mainWidth, 12);
     [UIView animateWithDuration:2 animations:^{
     _imgLine.frame = CGRectMake(_imgLine.frame.origin.x, _imgLine.frame.origin.y + _cameraView.innerViewRect.size.height - 6, _imgLine.frame.size.width, _imgLine.frame.size.height);
     }];
     */

    dispatch_async(dispatch_get_main_queue(), ^{
      if ([_imgLine.layer animationForKey:@"LineImgViewAnimation"]) {
          return;
      }

      // 调整位置
      {
          CGFloat corWidth = 16;
          CGFloat offsetTop = 0;

          float minX = CGRectGetMinX(_cameraView.innerViewRect);
          float maxX = CGRectGetMaxX(_cameraView.innerViewRect);
          float minY = CGRectGetMinY(_cameraView.innerViewRect);
          float maxY = CGRectGetMaxY(_cameraView.innerViewRect);

          _img1.frame = CGRectMake(minX, minY + self.config.areaTop + offsetTop, corWidth, corWidth);
          _img2.frame = CGRectMake(maxX - corWidth, minY + self.config.areaTop + offsetTop, corWidth, corWidth);
          _img3.frame = CGRectMake(minX, maxY - corWidth + self.config.areaTop + offsetTop, corWidth, corWidth);
          _img4.frame = CGRectMake(maxX - corWidth, maxY - corWidth + self.config.areaTop + offsetTop, corWidth, corWidth);

          _imgLine.frame = CGRectMake(0, _cameraView.innerViewRect.origin.y, mainWidth, 12);
      }

      // line移动的范围为 一个扫码框的高度(由于图片问题再减去图片的高度)
      CGFloat scanContent_layerH = _cameraView.innerViewRect.size.height;
      CGFloat lineimgViewH = _imgLine.frame.size.height;

      CABasicAnimation *lineAnimation = [self animationWith:@(0) toValue:@(scanContent_layerH - lineimgViewH) repCount:MAXFLOAT duration:1.5];
      [_imgLine.layer addAnimation:lineAnimation forKey:@"LineImgViewAnimation"];
      _imgLine.hidden = false;
    });
}

#pragma clang diagnostic pop

@end
